﻿using System;
using System.Collections.Generic;
using System.Text;

namespace TDD.SpreadSheet
{
    public class Spreadsheet
    {
        #region Constructors
        public Spreadsheet()
            : this("ZZ", 999)
        {
        }

        public Spreadsheet(string lastColumn, int lastRow)
        {
            if (!Cell.IsValidColumn(lastColumn))
            {
                throw new ArgumentException(string.Format("The column {0} is not a valid column format.", lastColumn), "lastColumn");
            }
            SpreadsheetCells = new Cell[lastRow, Cell.GetColumNumber(lastColumn)];
        }
        #endregion

        #region Properties
        private Cell[,] SpreadsheetCells
        { get; set; }
        #endregion

        #region Helper functions
        private Cell GetValidCell(string cell)
        {
            if (SpreadsheetCells == null)
            {
                throw new Exception("Spreadsheet is empty");
            }
            int row;
            int column;
            Cell.SplitColumnAndRow(cell, out column, out row);

            Cell validCell = null;
            try
            {
                validCell = SpreadsheetCells[row, column];

                if (validCell == null)
                {
                    validCell = new Cell();
                    SpreadsheetCells[row, column] = validCell;
                }

                return validCell;
            }
            catch (IndexOutOfRangeException ex)
            {
                throw new ArgumentException("Cell is out of range", ex);
            }
            catch (Exception ex)
            {
                throw new ArgumentException("Cell is not a valid cell", ex);
            }
        }
        private void SetValue(string value, Cell validCell)
        {
            validCell.Literal = value;

            //try to set int value
            int auxInt;
            if (int.TryParse(value, out auxInt))
            {
                validCell.Value = auxInt.ToString();
                return;
            }

            //try to set decimal value
            decimal auxDec;
            if (decimal.TryParse(value, out auxDec))
            {
                validCell.Value = auxDec.ToString();
                return;
            }

            if (value.Length > 0)
            {
                if (value.StartsWith("="))
                {
                    //the data is a formula
                    validCell.Value = EvaluateFormula(value);
                }
                else
                {
                    //the data is a string value
                    validCell.Value = value;
                }
            }
            else
            {
                //the data is a string value
                validCell.Value = value;
            }
        }
        private string EvaluateFormula(string literal)
        {
            //this method will be implemented in the next challenge
            return literal;
        }
        #endregion

        #region Public Functions
        public string Get(string cell)
        {
            return GetValidCell(cell).Value;
        }

        public string GetLiteral(string cell)
        {
            return GetValidCell(cell).Literal;
        }

        public void Put(String cell, string value)
        {
            if (value == null)
            {
                throw new ArgumentException("The cell value can not be null.", "value");
            }
            Cell validCell = GetValidCell(cell);
            if (validCell.Literal != value)
            {
                SetValue(value, validCell);
            }
        }
        #endregion
    }
}
